/*--------------------------------------------------------------------------
Modified from GNU Group's SDCC
Only for study purpose
---------------------------------------------------------------------------*/

#ifndef __COMPILER_GROUP_I_CODE_H
#define __COMPILER_GROUP_I_CODE_H

#include "set.h"
#include "value.h"
#include "SymbolTable.h"
extern set *iCodeChain;
#define SYNTAX_ERROR yylexerror("Syntax error")
#define ADDTOCHAIN(x) addSetHead(&iCodeChain,x)
#define IS_SYMOP(op) (op && op->type == SYMBOL)
#define IS_VALOP(op) (op && op->type == VALUE)
#define IS_TYPOP(op) (op && op->type == TYPE)
#define IS_ITEMP(op) (IS_SYMOP(op) && op->operand.symOperand->isitmp == 1)
#define IS_SYMOP(op) (op && op->type == SYMBOL)
#define IS_VALOP(op) (op && op->type == VALUE)
#define IS_TYPOP(op) (op && op->type == TYPE)
#define OP_SYMBOL(op)      op->operand.symOperand
#define OP_VALUE(op)       op->operand.valOperand
#define OP_SYM_TYPE(op)    op->operand.symOperand->type
#define OP_SYM_ETYPE(op)   op->operand.symOperand->etype
#define IS_TRUE_SYMOP(op) (op && IS_SYMOP(op) && !IS_ITEMP(op))
#define NAME_OP(op) op->operand.symOperand->name
#define VALUE_OP(op) ulFromVal(op->operand.valOperand)
#define PRINT_OP(op) (op?(op->type==SYMBOL?NAME_OP(op):itoa(VALUE_OP(op), labelbuffer, 10)):"")
#define GENRVALUEOP(op)		if (op->isaddr && IS_ITEMP (op)) op = geniCodeRValue(op, FALSE)
#define GENRVALUE GENRVALUEOP(left); GENRVALUEOP(right)
typedef enum
{
    SYMBOL = 1,
    VALUE,
    TYPE
} OPTYPE;

typedef struct operand
  {
    OPTYPE type;                /* type of operand */
    unsigned int isaddr:1;      /* is an address   */
    unsigned int aggr2ptr:2;    /* 1: must change aggregate to pointer to aggregate */
                                /* 2: aggregate has been changed to pointer to aggregate */
    unsigned int isvolatile:1;  /* is a volatile operand */
    unsigned int isGlobal:1;    /* is a global operand */
    unsigned int isPtr:1;       /* is assigned a pointer */
    unsigned int isGptr:1;      /* is a generic pointer  */
    unsigned int isParm:1;      /* is a parameter        */
    unsigned int isLiteral:1;   /* operand is literal    */

    int key;
    union
      {
        struct symbol *symOperand;      /* operand is of type symbol */
        struct value *valOperand;       /* operand is of type value  */
        struct sym_link *typeOperand;   /* operand is of type typechain */
      }
    operand;
	struct operand *next;	/* Use in call function */
  }
operand;


typedef struct iCode
{
	unsigned int op;            /* operation defined */
	int key;                    /* running key for this iCode */
	int seq;                    /* sequence number within routine */
	int seqPoint;               /* sequence point */
	short depth;                /* loop depth of this iCode */
	short level;                /* scope level */
	short block;                /* sequential block number */
	unsigned nosupdate:1;       /* don't update spillocation with this */
	unsigned generated:1;       /* code generated for this one */
	unsigned parmPush:1;        /* parameter push Vs spill push */
	unsigned supportRtn:1;      /* will cause a call to a support routine */
	unsigned regsSaved:1;       /* registers have been saved */
	unsigned bankSaved:1;       /* register bank has been saved */
	unsigned builtinSEND:1;     /* SEND for parameter of builtin function */

	struct iCode *next;         /* next in chain */
	struct iCode *prev;         /* previous in chain */
	set *movedFrom;             /* if this iCode gets moved to another block */
	int defKey;                 /* key for the operand being defined  */

	union
	{
		struct
		{
			struct operand *left;      /* left if any   */
			struct operand *right;     /* right if any  */
			struct operand *result;    /* result of this op */
		}
		lrr;

		struct
		{
			struct operand *condition; /* if this is a conditional */
			struct symbol *trueLabel;  /* true for conditional     */
			struct symbol *falseLabel; /* false for conditional    */
		}
		cnd;

		struct
		{
			struct operand *condition; /* condition for the jump */
			set *labels;        /* ordered set of labels  */
		}
		jmpTab;

	}
	ulrrcnd;

	symbol *label;              /* for a goto statement     */

	char *inlineAsm;            /* pointer to inline assembler code */

	int lineno;                 /* file & lineno for debug information */
	char *filename;

	int parmBytes;              /* if call/pcall, count of parameter bytes
								   on stack */
	int argreg;                 /* argument regno for SEND/RECEIVE */
	int eBBlockNum;             /* belongs to which eBBlock */
	char riu;                   /* after ralloc, the registers in use */
}iCode;

#define IC_RESULT(x) (x)->ulrrcnd.lrr.result
#define IC_LEFT(x)   (x)->ulrrcnd.lrr.left
#define IC_RIGHT(x)  (x)->ulrrcnd.lrr.right
#define IC_COND(x)   (x)->ulrrcnd.cnd.condition
#define IC_TRUE(x)   (x)->ulrrcnd.cnd.trueLabel
#define IC_FALSE(x)  (x)->ulrrcnd.cnd.falseLabel
#define IC_LABEL(x)  (x)->label

operand *geniCodeArray (operand * left, operand * right);
operand *geniCodeSubtract (operand * left, operand * right);
operand *geniCodePtrPtrSubtract (operand * left, operand * right);
operand *geniCodeAssign (operand * left, operand * right);
operand *geniCodePostInc (operand * op);
operand * geniCodeCast (sym_link * type, operand * op, bool implicit);
operand *newiTempOperand (sym_link * type, char throwType);
operand *geniCodeDerefPtr (operand * op, int lvl);
iCode *newiCode (int op, operand * left, operand * right);
sym_link *operandType (operand * op);
void geniCodeLabel (symbol * label);
void geniCodeGoto (symbol * label);
void iCodePrintAll(iCode *ic, char *filename);
void iCodePrint(iCode *ic, FILE *f);
#endif